#include<stdio.h>
#include<string.h>
#include<conio.h>
#include <graphics.h>
#include <time.h>
#include <windows.h>//sleep()函数
#include<mmsystem.h>

// 引用 Windows Multimedia API
#pragma comment(lib,"Winmm.lib")

int map[6][6];
//用来记录图片数据
IMAGE imgs[10];//不同照片
int score = 0;//得分
int level = 1; // 当前关卡序号
int maxTime; // 这一关游戏的总时长
int remainTime, remainTIME; // 剩余时间
int TIME = 10;//图片展示用于记忆时间
int tips = 3;//提示次数
clock_t start, end;// 用于计时的变量
clock_t begin, finish;// 用于计时的变量

void writeRecordFile(int score); //保存最高分数据文件
int readRecordFile(); //读取最高分数据文件
void number_write(int number_size, int x, int y, int number, COLORREF color);//设置字体的样式，大小，颜色以及位置
void set_maps();//地图初始化
void updateWithoutInput();  // 与用户输入无关的更新
int plays();//游戏过程
int begin_menu();//开始界面
int game_over(int result);//游戏结束
void help();//游戏帮助
void returnplay();//继续游戏

void writeRecordFile(int score)  //保存最高分数据文件
{
	FILE* fp;
	fopen_s(&fp,".\\gameRecord.dat", "w");
	fprintf(fp, "%d", score);
	fclose(fp);
}

int readRecordFile()  //读取最高分数据文件
{
	int score;
	FILE* fp;
  fopen_s(&fp,".\\gameRecord.dat", "r");

	// 如果打不开的话，就新建一个文件，其得分记录为0分
	if (fp == NULL)
	{
		writeRecordFile(0);
		return 0;
	}
	else // 能打开这个文件，就读取下最高分记录
	{
		fscanf_s(fp, "%d", &score);
		fclose(fp);
		return score;
	}
}

void number_write(int number_size, int x, int y, int number, COLORREF color)
{//设置字体的样式，大小，颜色以及位置
	TCHAR s[30];
	_stprintf_s(s, _T("%d"), number);//需要先把数字进行交换
	settextstyle(number_size, 0, _T("黑体"));//设置字体样式为黑体
	settextcolor(color);//字体颜色
	outtextxy(x, y, s);// 在指定位置输出字符串
}

void set_maps()
{//地图初始化
	IMAGE back;//游戏背景
	initgraph(800, 600);//地图大小
	setlinecolor(WHITE);
	setfillcolor(BLACK);
	fillrectangle(602, 1, 799, 599);

	int x, y, i;
	int number[8] = { 0 };//图片出现次数
	srand((unsigned int)time(NULL));//随机数种子
	for (x = 0; x < 6; x++)
	{
		for (y = 0; y < 6; y++)
		{
			while (1)
			{
				i = rand() % 8;
				//图片随机分布
				if (number[i] < 4 && i < 6)
				{
					number[i]++;
					map[x][y] = i + 1;
					break;
				}
				if (number[i] < 6 && i >= 6)
				{
					number[i]++;
					map[x][y] = i + 1;
					break;
				}
			}
		}
	}

	settextstyle(30, 0, _T("黑体"));
	settextcolor(YELLOW);
	outtextxy(605, 0, _T("当前关卡"));
	outtextxy(605, 100, _T("当前用时"));
	outtextxy(605, 200, _T("点击次数"));
	outtextxy(605, 300, _T("当前分数"));
	outtextxy(605, 400, _T("帮助"));
	loadimage(&back, _T("back.jpg"), 160, 50);
	putimage(620, 500, &back);//返回键的设置
}

void updateWithoutInput()  // 与用户输入无关的更新
{
	loadimage(&imgs[0], _T("0.jpg"), 100, 100);
	loadimage(&imgs[1], _T("1.jpg"), 100, 100);
	loadimage(&imgs[2], _T("2.jpg"), 100, 100);
	loadimage(&imgs[3], _T("3.jpg"), 100, 100);
	loadimage(&imgs[4], _T("4.jpg"), 100, 100);
	loadimage(&imgs[5], _T("5.jpg"), 100, 100);
	loadimage(&imgs[6], _T("6.jpg"), 100, 100);
	loadimage(&imgs[7], _T("7.jpg"), 100, 100);
	loadimage(&imgs[8], _T("8.jpg"), 100, 100);
	loadimage(&imgs[9], _T("yuanshi.jpg"), 100, 100);
	//背景图

	begin = clock();//计时
	for (int x = 0; x < 6; x++)
	{
		for (int y = 0; y < 6; y++)
		{
			putimage(100 * y, 100 * x, &imgs[map[x][y]]);//先放满游戏图片
			Sleep(100);
		}
	}
	Sleep(2);
	finish = clock();
	remainTIME = (int)((finish - begin) / CLK_TCK);
	if (remainTIME >= TIME)
	{
		plays();
	}

		if (score > readRecordFile())
		{
			// 更新下得分记录
			writeRecordFile(score);
			// 显示恭喜超过记录
			settextcolor(RGB(255, 0, 0));
			settextstyle(100, 0, _T("黑体"));
			outtextxy(0, 0, _T("恭喜打破得分记录"));
			FlushBatchDraw(); // 批量绘制
			Sleep(2000);
		}
}

int plays()
{//游戏过程
	number_write(30, 650, 50, level, WHITE);
	for (int x = 0; x < 6; x++)
	{
		for (int y = 0; y < 6; y++)
		{
			putimage(100 * y, 100 * x, &imgs[0]);//放满最初背景图
			Sleep(25);
		}
	}

	mciSendString("open 点击声效.mp3 alias click", NULL, 0, NULL);

	MOUSEMSG mouse;
	int x, y;//鼠标数组下标
	int times = 0;//点击次数
	number_write(30, 650, 250, times, WHITE);//点击次数显示显示
	int t, x0 = -1, y0 = -1;
	int jishuqi = 0;
	number_write(30, 650, 350, score, WHITE);//得分显示
	number_write(30, 650, 450, tips, WHITE);//剩余帮助次数显示
	start = clock();//计时

	while (1)
	{
		mouse = GetMouseMsg(); //返回保存有鼠标消息的结构体
		if (mouse.uMsg == WM_LBUTTONDOWN)//左键按下消息
		{
			mciSendString("close click", NULL, 0, NULL);
			mciSendString("open 点击声效.mp3 alias click", NULL, 0, NULL);
			mciSendString("play click", NULL, 0, NULL);
			//当点击时，产生点击音效
			x = mouse.y / 100;
			y = mouse.x / 100;
			if (mouse.x >= 620 && mouse.x <= 780 && mouse.y >= 500 && mouse.y <= 550)//返回
			{
				return 0;
			}
			else if (mouse.x >= 605 && mouse.x <= 665 && mouse.y >= 400 && mouse.y <= 430)//帮助
			{
				if (tips >0)
				{
					tips--;
					number_write(30, 650, 450, tips, WHITE);//剩余帮助次数显示
					help();//帮助
					returnplay();//继续游戏
				}
			}

			else if (map[x][y] != 0 && mouse.x < 600)//防止点击到右边界面
			{
				if (((x0 != x) | (y0 != y)))//保证两次点击的不是同一张图片
				{
					times++;
					putimage(100 * y, 100 * x, &imgs[map[x][y]]);
					number_write(30, 650, 250, times, WHITE);
				}
				if (times % 2 == 0)//点击次数为偶数
				{
					if (map[x][y] != t)//两次图片不相同
					{
						Sleep(100);
						putimage(100 * y0, 100 * x0, &imgs[0]);
						putimage(100 * y, 100 * x, &imgs[0]);//绘制原始背景图
						t = -1;
						x0 = -1;
						y0 = -1;
						if (score > 0)
						{
							score --;
							number_write(30, 650, 350, score, WHITE);//分数减一
						}
					}
					else if (map[x][y] == t && ((x0 != x) | (y0 != y)))//两次图片相同
					{
						Sleep(100);
						putimage(100 * y0, 100 * x0, &imgs[9]);
						putimage(100 * y, 100 * x, &imgs[9]);//图片变成黑色
						map[x][y] = 0;
						map[x0][y0] = 0;
						jishuqi += 2;//消灭图片数加二
						score += 4;
						number_write(30, 650, 350, score, WHITE);//分数加四
					}
				}
				else if (times % 2 == 1 && ((x0 != x) | (y0 != y)))
				{
					t = map[x][y];//记录上次点击的数字
					x0 = x;
					y0 = y;
				}
			}
		}
		Sleep(2);

		end = clock();
		remainTime = (int)((end - start) / CLK_TCK);
		number_write(30, 650, 150, remainTime, WHITE);//时间显示
		maxTime =200 - level * 10; 
		// 每一关游戏设定的总时长，每关时长-10秒
		if (remainTime >= maxTime)//时间到，游戏失败
		{
			return 0;
		}
		if (jishuqi == 36)//当图片全部消灭时成功
		{
			return 1;
		}
	}
}

int begin_menu()
{//开始界面
	initgraph(1152, 648);//整个游戏界面绘制
	IMAGE menu;//开始菜单图片
	loadimage(&menu, _T("begin_menu0.jpg"), 1152, 648);
	IMAGE shuoming;//游戏说明
	loadimage(&shuoming, _T("begin_menu01.jpg"), 1152, 648);
	putimage(0, 0, &menu);//绘制菜单界面
	mciSendString("open 点击声效.mp3 alias click", NULL, 0, NULL);

	MOUSEMSG mouse;
	MOUSEMSG mouse2;
	int x2, y2;
	int x, y;
	while (1)
	{
		mouse = GetMouseMsg();
		if (mouse.uMsg == WM_LBUTTONDOWN)//左键按下
		{
			mciSendString("close click", NULL, 0, NULL);
			mciSendString("open 点击声效.mp3 alias click", NULL, 0, NULL);
			mciSendString("play click", NULL, 0, NULL);
			//当点击图片时，产生点击音效
			x = mouse.x;
			y = mouse.y;
			//记录鼠标坐标来确定所点击的图片
			if (x <= 635 && x >= 461 && y >= 185 && y <= 238)//开始游戏
			{
				break;
			}

			else if (x <= 635 && x >= 461 && y >= 281 && y <= 330)//说明
			{
				cleardevice;
				putimage(0, 0, &shuoming);//绘制说明界面
				while (1)
				{
					mouse2 = GetMouseMsg();
					if (mouse2.uMsg == WM_LBUTTONDOWN)//按下左键
					{
						mciSendString("close click", NULL, 0, NULL);
						mciSendString("open 点击声效.mp3 alias click", NULL, 0, NULL);
						mciSendString("play click", NULL, 0, NULL);
						//当点击图片时，产生点击音效
						mouse2 = GetMouseMsg();
						x2 = mouse2.x;
						y2 = mouse2.y;//鼠标坐标
						if (x2 <= 228 && x2 >= 52 && y2 >= 15 && y2 <= 65)//返回
						{
							putimage(0, 0, &menu);//绘制菜单界面
							break;
						}
					}
					Sleep(10);
				}
				continue;
			}
		}
		Sleep(10);
	}
	return 0;
	closegraph();
}

//游戏结束
int game_over(int result)//1返回，0下一关
{
	IMAGE over[2];//游戏结果
	loadimage(&over[0], _T("success.jpg"), 500, 350);//游戏成功界面
	loadimage(&over[1], _T("failed.jpg"), 500, 350);//游戏失败界面
	mciSendString("open 点击声效.mp3 alias click", NULL, 0, NULL);
	mciSendString("open 游戏胜利.mp3 alias success", NULL, 0, NULL);
	mciSendString("open 游戏失败.mp3 alias failure", NULL, 0, NULL);

	if (result == 1)//游戏成功
	{
		mciSendString("play success", NULL, 0, NULL);
		putimage(50, 125, &over[0]);//绘制游戏成功界面
		MOUSEMSG mouse;
		int x, y;
		while (1)
		{
			mouse = GetMouseMsg();
			if (mouse.uMsg == WM_LBUTTONDOWN)//按下左键
			{
				mciSendString("close click", NULL, 0, NULL);
				mciSendString("open 点击声效.mp3 alias click", NULL, 0, NULL);
				mciSendString("play click", NULL, 0, NULL);
				//当点击时，产生点击音效
				x = mouse.x;
				y = mouse.y;
				//鼠标坐标
				if (x >= 200 && x <= 304 && y >= 248 && y <= 286)//返回
				{
					return 1;
				}
				else if (x >= 383 && x <= 486 && y >= 248 && y <= 286)//下一关
				{
					return 0;
				}
			}
			Sleep(10);
		}
	}

	else
	{//失败
		mciSendString("play failure", NULL, 0, NULL);
		putimage(50, 125, &over[1]);//绘制游戏失败界面
		MOUSEMSG mouse1;
		int x1, y1;
		while (1)
		{
			mouse1 = GetMouseMsg();
			if (mouse1.uMsg == WM_LBUTTONDOWN)//按下左键
			{
				mciSendString("close click", NULL, 0, NULL);
				mciSendString("open 点击声效.mp3 alias click", NULL, 0, NULL);
				mciSendString("play click", NULL, 0, NULL);
				//当点击时，产生点击音效
				x1 = mouse1.x;
				y1 = mouse1.y;//鼠标坐标
				if (x1 >= 204 && x1 <= 412 && y1 >= 340 && y1 <= 405)//返回
				{
					return 1;
				}
			}
			Sleep(10);
		}
	}
}

void help()		//帮助界面
{
	int x, y;
	for (x = 0; x < 6; x++)
	{
		for (y = 0; y < 6; y++)
		{
			if (map[x][y] != 0)
			{
				putimage(100 * y, 100 * x, &imgs[map[x][y]]);//显示图片
				Sleep(25);
			}
		}
	}
	Sleep(1000);
}

void returnplay()//继续游戏
{
	int x, y;
	for (x = 0; x < 6; x++)
	{
		for (y = 0; y < 6; y++)
		{
			if (map[x][y] != 0)
			{
				putimage(100 * y, 100 * x, &imgs[0]);//返回背景图片
				Sleep(25);
			}
		}
	}
	Sleep(2);
}

int main()
{//主函数
begin1:mciSendString("open 背景音乐.mp3 alias bkmusic", NULL, 0, NULL);
	mciSendString("play bkmusic repeat", NULL, 0, NULL);//循环播放背景音乐
	begin_menu();

begin2:set_maps();//开始地图
	updateWithoutInput();
	int result = plays();//1返回，0下一关
	int choice = game_over(result);//游戏选择
	if (choice == 1)
	{
		closegraph();
		initgraph(1152, 648);
		score = 0;
		goto begin1;
		//当点击返回时， 转去执行语句begin1所标识的语句，重新绘制游戏界面
	}

	if (choice == 0)
	{
		level++;
		tips = 3;
		goto begin2;
		//当点击下一关时， 转去执行语句begin2所标识的语句，继续下一关
	}

	system("pause"); //暂停程序的执行，等待任意健继续执行
	return 0;
}